package com.wsoft.hr.pm.config;

import cn.hutool.core.util.IdUtil;
import com.wsoft.bpm.constants.BpmConstant;
import com.wsoft.bpm.controller.BpmDefController;
import com.wsoft.bpm.dto.ActModelDTO;
import com.wsoft.bpm.dto.ActModelDataDTO;
import com.wsoft.bpm.enums.BranchType;
import com.wsoft.bpm.enums.ExecuteCategory;
import com.wsoft.bpm.enums.ListenerEvent;
import com.wsoft.bpm.enums.ListenerType;
import com.wsoft.bpm.query.node.*;
import com.wsoft.bpm.service.IActReModelService;
import com.wsoft.bpm.service.IActWorkflowConfigService;
import com.wsoft.bpm.utils.ActivityUtils;
import com.wsoft.hr.pm.enums.HrProcessFlowStageEnum;
import com.wsoft.service.IMemberCommonService;
import lombok.SneakyThrows;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.repository.Model;
import org.activiti.engine.repository.ProcessDefinition;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.Resource;

/**
 * 绩效系统初始化模型监听器
 *
 * @Author zhonglj
 * @Date 2025/3/3 18:34
 */
@Component
public class HrInitModelListener implements ApplicationListener<ApplicationReadyEvent> {
    @Resource
    private IActReModelService actReModelService;
    @Resource
    private RepositoryService repositoryService;

    @SneakyThrows
    @Override
    public void onApplicationEvent(ApplicationReadyEvent event) {
        for (HrProcessFlowStageEnum stage : HrProcessFlowStageEnum.values()) {
            Model model = repositoryService.createModelQuery().modelKey(stage.getProcessDefKey()).singleResult();
            String modelId = null;
            // 流程模型
            if (model == null) {
                ActModelDTO modelDTO = new ActModelDTO();
                modelDTO.setDesc(stage.getDesc());
                modelDTO.setCategory("绩效系统");
                modelDTO.setKey(stage.getProcessDefKey());
                modelDTO.setName("绩效系统-" + stage.getDesc());
                modelId = actReModelService.createModel(modelDTO);
            } else {
                modelId = model.getId();
            }

            // 流程设计
            byte[] modelEditorSource = repositoryService.getModelEditorSource(modelId);
            if (modelEditorSource == null) {
                // 模型尚未保存流程设计
                String dataXml = createHrProcDefData(stage.getProcessDefKey(), modelId, stage.getChainKey());
                ActModelDataDTO modelDataDTO = new ActModelDataDTO();
                modelDataDTO.setModelId(modelId);
                modelDataDTO.setData(dataXml);
                actReModelService.saveModelData(modelDataDTO);
            }

            // 流程部署
            ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
                    .processDefinitionKey(stage.getProcessDefKey())
                    .latestVersion()
                    .singleResult();

            if (processDefinition == null) {
                actReModelService.deploy(modelId);
            }
        }
    }

    @Resource
    private BpmDefController bpmDefController;
    @Resource
    private IActWorkflowConfigService actWorkflowConfigService;
    @Resource
    private IMemberCommonService memberCommonService;

    private String createHrProcDefData(String procDefKey, String modelId, String chainKey) throws Exception {
        // 创建模拟请求对象
        MockHttpServletRequest mockRequest = new MockHttpServletRequest();
        // 设置请求上下文
        RequestContextHolder.setRequestAttributes(new ServletRequestAttributes(mockRequest));
        UserDetails userDetails = memberCommonService.loadUserByUsername("admin");
        UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
        SecurityContextHolder.getContext().setAuthentication(authentication);

        try {
            String startEventId = BpmConstant.GENERATE_ID_PREFIX_START_EVENT + IdUtil.fastSimpleUUID();
            String userTaskId = BpmConstant.GENERATE_ID_PREFIX_USERTASK + IdUtil.fastSimpleUUID();
            String endEventId = BpmConstant.GENERATE_ID_PREFIX_END_EVENT + IdUtil.fastSimpleUUID();
            String flow1 = BpmConstant.GENERATE_ID_PREFIX_SEQUENCE_FLOW + IdUtil.fastSimpleUUID();
            String flow2 = BpmConstant.GENERATE_ID_PREFIX_SEQUENCE_FLOW + IdUtil.fastSimpleUUID();
            String data = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
                    "<definitions " +
                    "xmlns:bpmn=\"http://www.omg.org/spec/BPMN/20100524/MODEL\" " +
                    "xmlns=\"http://www.omg.org/spec/BPMN/20100524/MODEL\" " +
                    "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" " +
                    "xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" " +
                    "xmlns:activiti=\"http://activiti.org/bpmn\" " +
                    "xmlns:bpmndi=\"http://www.omg.org/spec/BPMN/20100524/DI\" " +
                    "xmlns:omgdc=\"http://www.omg.org/spec/DD/20100524/DC\" " +
                    "xmlns:omgdi=\"http://www.omg.org/spec/DD/20100524/DI\" " +
                    "typeLanguage=\"http://www.w3.org/2001/XMLSchema\" " +
                    "expressionLanguage=\"http://www.w3.org/1999/XPath\" " +
                    "targetNamespace=\"http://www.activiti.org/test\">\n" +
//                "  <bpmn:process id=\"" + procDefKey + "\" name=\"" + procDefKey + "\" isExecutable=\"true\">\n" +
                    bpmDefController.process(new ProcessQuery()
                            .setModelId(modelId)
                            .setId(procDefKey)
                            .setName(procDefKey)
                    ).getData().replace("</bpmn:process>", "") + "\n" +
//                "<bpmn:startEvent id=\"StartEvent211eea3755df49639a2409c7e4378e5a\" name=\"开始\" activiti:initiator=\"\" />\n" +
                    bpmDefController.startEvent(new StartEventQuery()
                            .setModelId(modelId)
                            .setId(startEventId)
                            .setName("开始")
                    ).getData() + "\n" +
//                "        <bpmn:userTask id=\"UserTaskead5d78599ac483b893bf1f2a449df60\" name=\"动态审批\" activiti:formKey=\"\" activiti:assignee=\"system\" activiti:priority=\"50\" activiti:skipExpression=\"\">\n" +
//                "            <bpmn:documentation>审批</bpmn:documentation>\n" +
//                "            <bpmn:extensionElements>\n" +
//                "                <activiti:taskListener expression=\"${expressionListenerBean.createDynamicApprovalChain(task,&#39;kamui&#39;)}\" event=\"create\" />\n" +
//                "            </bpmn:extensionElements>\n" +
//                "        </bpmn:userTask>\n" +
                    bpmDefController.task(new TaskQuery()
                            .setModelId(modelId)
                            .setId(userTaskId)
                            .setName("动态审批")
                            .setBranchType(BranchType.AUTO.getValue())
                            .setPriority("50")
                            .setExecuteCategory(ExecuteCategory.EXECUTE.getValue())
                            .setTaskExecute(new TaskExecuteQuery().setExpression("system"))
                            .setListeners(actWorkflowConfigService.addListener(
                                    null,
                                    ListenerEvent.TASK_CREATE.getValue(),
                                    ListenerType.EXPRESSION.getValue(),
                                    "${expressionListenerBean.createDynamicApprovalChain(task,'" + chainKey + "')}",
                                    "初始化动态审批"))
                    ).getData() + "\n" +
//                "        <bpmn:sequenceFlow id=\"Flow_124j939\" sourceRef=\"StartEvent211eea3755df49639a2409c7e4378e5a\" targetRef=\"UserTaskead5d78599ac483b893bf1f2a449df60\" />\n" +
                    bpmDefController.sequenceFlow(new SequenceFlowQuery()
                            .setModelId(modelId)
                            .setId(flow1)
                            .setSourceRef(startEventId)
                            .setTargetRef(userTaskId)
                    ).getData() + "\n" +
//                "        <bpmn:sequenceFlow id=\"Flow_048x3xu\" sourceRef=\"UserTaskead5d78599ac483b893bf1f2a449df60\" targetRef=\"EndEvent2e35dcc7340a4076ac891a4a64408c3d\" />\n" +
                    bpmDefController.sequenceFlow(new SequenceFlowQuery()
                            .setModelId(modelId)
                            .setId(flow2)
                            .setSourceRef(userTaskId)
                            .setTargetRef(endEventId)
                    ).getData() + "\n" +
//                "        <bpmn:endEvent id=\"EndEvent2e35dcc7340a4076ac891a4a64408c3d\" name=\"结束\">\n" +
//                "            <bpmn:extensionElements>\n" +
//                "                <activiti:executionListener delegateExpression=\"${processEndCallBackListener}\" event=\"end\" />\n" +
//                "            </bpmn:extensionElements>\n" +
//                "            <bpmn:incoming>Flow_048x3xu</bpmn:incoming>\n" +
//                "        </bpmn:endEvent>" +
                    bpmDefController.endEvent(new EndEventQuery()
                            .setModelId(modelId)
                            .setId(endEventId)
                            .setName("结束")
                            .setListeners(actWorkflowConfigService.addListener(
                                    null,
                                    ListenerEvent.EXECUTION_END.getValue(),
                                    ListenerType.DELEGATE_EXPRESSION.getValue(),
                                    "${processEndCallBackListener}",
                                    "流程正常结束监听器"))
                    ).getData() + "\n" +
                    "  </bpmn:process>\n" +

                    "<bpmndi:BPMNDiagram id=\"BPMNDiagram_1\">\n" +
                    "        <bpmndi:BPMNPlane id=\"BPMNPlane_1\" bpmnElement=\"" + procDefKey + "\">\n" +
                    "            <bpmndi:BPMNShape id=\"_BPMNShape_" + startEventId + "\" bpmnElement=\"" + startEventId + "\">\n" +
                    "                <omgdc:Bounds x=\"2\" y=\"132\" width=\"36\" height=\"36\" />\n" +
                    "                <bpmndi:BPMNLabel>\n" +
                    "                    <omgdc:Bounds x=\"9\" y=\"175\" width=\"23\" height=\"14\" />\n" +
                    "                </bpmndi:BPMNLabel>\n" +
                    "            </bpmndi:BPMNShape>\n" +
                    "            <bpmndi:BPMNShape id=\"" + userTaskId + "_di\" bpmnElement=\"" + userTaskId + "\">\n" +
                    "                <omgdc:Bounds x=\"100\" y=\"125\" width=\"100\" height=\"50\" />\n" +
                    "                <bpmndi:BPMNLabel />\n" +
                    "            </bpmndi:BPMNShape>\n" +
                    "            <bpmndi:BPMNShape id=\"" + endEventId + "_di\" bpmnElement=\"" + endEventId + "\">\n" +
                    "                <omgdc:Bounds x=\"252\" y=\"132\" width=\"36\" height=\"36\" />\n" +
                    "                <bpmndi:BPMNLabel>\n" +
                    "                    <omgdc:Bounds x=\"260\" y=\"175\" width=\"23\" height=\"14\" />\n" +
                    "                </bpmndi:BPMNLabel>\n" +
                    "            </bpmndi:BPMNShape>\n" +
                    "            <bpmndi:BPMNEdge id=\"" + flow1 + "_di\" bpmnElement=\"" + flow1 + "\">\n" +
                    "                <omgdi:waypoint x=\"38\" y=\"150\" />\n" +
                    "                <omgdi:waypoint x=\"100\" y=\"150\" />\n" +
                    "            </bpmndi:BPMNEdge>\n" +
                    "            <bpmndi:BPMNEdge id=\"" + flow2 + "_di\" bpmnElement=\"" + flow2 + "\">\n" +
                    "                <omgdi:waypoint x=\"200\" y=\"150\" />\n" +
                    "                <omgdi:waypoint x=\"252\" y=\"150\" />\n" +
                    "            </bpmndi:BPMNEdge>\n" +
                    "        </bpmndi:BPMNPlane>\n" +
                    "    </bpmndi:BPMNDiagram>" +

                    "</definitions>";
            String formatXml = ActivityUtils.formatXml(data);
            return formatXml;
        } finally {
            // 清理请求上下文
            RequestContextHolder.resetRequestAttributes();
        }
    }
}
